package com.jevons.muffin.util;

import android.app.DownloadManager;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Environment;
import android.text.TextUtils;
import android.text.format.Formatter;


import com.jevons.muffin.BaseApplication;
import com.jevons.muffin.utilcode.LogUtils;
import com.jevons.muffin.utilcode.StringUtils;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.nio.channels.FileChannel;
import java.util.Locale;
import java.util.Properties;

/**
 * @author linaisheng
 * Created at 2019/11/4.
 */
public final class FileUtil {

    private static final String TAG = FileUtil.class.getSimpleName();

    public static final double KB = 1024.0;
    public static final double MB = KB * KB;
    public static final double GB = KB * KB * KB;



    public static String createCacheRootPath(Context context) {
        String cacheRootPath = "";
        if (FileUtil.isSDCardExist()) {
            // /sdcard/Android/data/<application package>/cache
            cacheRootPath = context.getExternalCacheDir().getPath();
        } else {
            // /data/data/<application package>/cache
            cacheRootPath = context.getCacheDir().getPath();
        }
        return cacheRootPath;
    }

    /**
     * 关闭IO流
     *
     * @param closeables
     */
    public static void closeIO(Closeable... closeables) {
        if (null == closeables || closeables.length <= 0) {
            return;
        }
        for (Closeable cb : closeables) {
            try {
                if (null == cb) {
                    continue;
                }
                cb.close();
            } catch (IOException e) {
                LogUtils.printErrorTag(TAG, e.toString());
            }
        }
    }

    /**
     * 获取文件的Size
     *
     * @param filepath 文件路径
     * @return
     */
    public static long getFileSize(String filepath) {
        if (TextUtils.isEmpty(filepath)) {
            return -1;
        }
        File file = new File(filepath);
        return (file.exists() && file.isFile() ? file.length() : -1);
    }

    /**
     * 计算文件夹的大小
     *
     * @param file 文件夹
     * @return
     */
    public static long getFolderSize(File file) {
        long size = 0;
        if (!file.exists()) {
            return size;
        }

        File[] listFiles = file.listFiles();
        for (int i = 0; i < listFiles.length; i++) {
            if (listFiles[i].isDirectory()) {
                size += getFolderSize(listFiles[i]);
            } else {
                size += listFiles[i].length();
            }
        }
        return size;
    }

    /**
     * 获取文件名称
     *
     * @param filePath 文件路径
     * @return 文件名称
     */
    public static String getFileName(String filePath) {
        if (StringUtils.isEmpty(filePath)) {
            return filePath;
        }

        int filePosi = filePath.lastIndexOf(File.separator);
        return (filePosi == -1) ? filePath : filePath.substring(filePosi + 1);
    }

    /**
     * 获取文件夹名称
     *
     * @param filePath 文件路径
     * @return 文件夹名称
     */
    public static String getFolderName(String filePath) {
        if (filePath == null || filePath.length() == 0 || filePath.trim().length() == 0) {
            return filePath;
        }
        int filePos = filePath.lastIndexOf(File.separator);
        return (filePos == -1) ? "" : filePath.substring(0, filePos);
    }

    /**
     * 重名名文件\文件夹
     *
     * @param filepath 文件夹路径
     * @param newName  新的名字
     * @return true 重命名成功
     */
    public static boolean renameFile(String filepath, String newName) {
        File file = new File(filepath);
        return file.exists() && file.renameTo(new File(newName));
    }

    /**
     * 创建文件夹
     *
     * @param filePath 文件夹路径
     * @return
     */
    public static boolean createFolder(String filePath) {
        return createFolder(filePath, false);
    }

    /**
     * 创建文件夹（支持覆盖原来的文件夹）
     *
     * @param filePath 文件夹路径
     * @param recreate 是否覆盖原先的文件夹（true-覆盖）
     * @return
     */
    public static boolean createFolder(String filePath, boolean recreate) {
        String folderName = getFolderName(filePath);
        if (folderName == null || folderName.length() == 0 || folderName.trim().length() == 0) {
            return false;
        }
        File folder = new File(folderName);
        if (folder.exists()) {
            if (recreate) {
                deleteFile(folderName);
                return folder.mkdirs();
            } else {
                return true;
            }
        } else {
            return folder.mkdirs();
        }
    }

    /**
     * 清除指定文件及目录
     *
     * @param file 需要清除的文件夹
     * @return
     */
    public static boolean cleanDirectory(File file) {
        return deleteFile(file);
    }

    /**
     * 删除文件夹
     *
     * @param path 文件夹路径
     */
    public static void deleteFile(String path) {
        if (StringUtils.isEmpty(path)) {
            return;
        }
        deleteFile(new File(path));
    }

    /**
     * 删除指定目录下的文件及目录
     *
     * @param file 文件夹
     * @return
     */
    public static boolean deleteFile(File file) {
        if (!file.exists()) {
            return true;
        }

        if (file.isDirectory()) {
            File[] childFiles = file.listFiles();

            for (int i = 0; i < childFiles.length; i++) {
                deleteFile(childFiles[i]);
            }
        }

        return file.delete();
    }

    /**
     * 获取-指定路径-的父目录
     *
     * @param path 文件路径
     * @return 父目录路径
     */
    public static String getDirectoryName(String path) {
        if (!StringUtils.isEmpty(path)) {
            File file = new File(path);
            if (file.exists()) {
                path = file.getParent();
                return path.substring(path.lastIndexOf(File.separator) + 1);
            }
        }
        return "";
    }

    /**
     * 获取动态获取缓存目录
     *
     * @param context 上下文
     * @return 如果SD卡可用，就返回外部缓存目录，否则返回机身自带缓存目录
     */
    public static File getDynamicCacheDir(Context context) {
        if (isSDCardExist()) {
            File dir = context.getExternalCacheDir();
            if (dir == null) {
                dir = context.getCacheDir();
            }
            return dir;
        } else {
            return context.getCacheDir();
        }
    }

    /**
     * 将文本内容写入文件
     *
     * @param file    文件
     * @param content 内容
     * @param append  是否在原先的文件上追加内容（false-则覆盖原先的文件）
     * @return true 写入成功
     */
    public static boolean writeFile(File file, String content, boolean append) {
        return writeFile(file.getPath(), content, append);
    }

    /**
     * 将文本内容写入文件
     *
     * @param filename 文件名称
     * @param content  内容
     * @param append   是否在原先的文件上追加内容（false-则覆盖原先的文件）
     * @return true 写入成功
     */
    public static boolean writeFile(String filename, String content, boolean append) {
        boolean isSuccess = false;
        BufferedWriter bufferedWriter = null;
        try {
            bufferedWriter = new BufferedWriter(new FileWriter(filename, append));
            bufferedWriter.write(content);
            isSuccess = true;
        } catch (IOException e) {
            LogUtils.printWarnTag(TAG, e.toString());
        } finally {
            closeIO(bufferedWriter);
        }
        return isSuccess;
    }

    /**
     * 读取文件
     *
     * @param filename 文件名称
     * @return String 文件内容
     */
    public static String readFile(String filename) {
        File file = new File(filename);
        BufferedReader bufferedReader = null;
        String str = null;
        try {
            if (file.exists()) {
                bufferedReader = new BufferedReader(new FileReader(filename));
                str = bufferedReader.readLine();
            }
        } catch (IOException e) {
            LogUtils.printWarnTag(TAG, e.toString());
        } finally {
            closeIO(bufferedReader);
        }
        return str;
    }

    /**
     * 从文件中读取字符串(可设置编码)
     *
     * @param file        文件
     * @param charsetName 编码名称
     * @return 文件内容
     */
    public static String readFile(File file, String charsetName) {
        StringBuilder fileContent = new StringBuilder("");
        if (file == null || !file.isFile()) {
            return null;
        }
        BufferedReader reader = null;
        try {
            InputStreamReader is = new InputStreamReader(new FileInputStream(file), charsetName);
            reader = new BufferedReader(is);
            String line = null;
            while ((line = reader.readLine()) != null) {
                if (!fileContent.toString().equals("")) {
                    fileContent.append("\r\n");
                }
                fileContent.append(line);
            }
            return fileContent.toString();
        } catch (IOException e) {
            throw new RuntimeException("IOException occurred. ", e);
        } finally {
            closeIO(reader);
        }
    }

    /**
     * 将输入流写入到文件
     *
     * @param is   流
     * @param file 被写入流的文件
     */
    public static void stream2File(InputStream is, File file) {
        byte[] b = new byte[1024];
        int len;
        FileOutputStream os = null;
        try {
            os = new FileOutputStream(file);
            while ((len = is.read(b)) != -1) {
                os.write(b, 0, len);
                os.flush();
            }
        } catch (IOException e) {
            LogUtils.printWarnTag(TAG, e.toString());
        } finally {
            closeIO(is, os);
        }
    }

    /**
     * 复制文件
     *
     * @param in  输入流
     * @param out 输出流
     */
    public static void copyFile(InputStream in, OutputStream out) {
        try {
            byte[] b = new byte[2 * 1024 * 1024]; //2M memory
            int len = -1;
            while ((len = in.read(b)) > 0) {
                out.write(b, 0, len);
                out.flush();
            }
        } catch (IOException e) {
            LogUtils.printWarnTag(TAG, e.toString());
        } finally {
            closeIO(in, out);
        }
    }

    /**
     * 快速复制
     *
     * @param in  File-in
     * @param out File-out
     */
    public static void copyFileFast(File in, File out) {
        FileChannel filein = null;
        FileChannel fileout = null;
        try {
            filein = new FileInputStream(in).getChannel();
            fileout = new FileOutputStream(out).getChannel();
            filein.transferTo(0, filein.size(), fileout);
        } catch (FileNotFoundException e) {
            LogUtils.printWarnTag(TAG, e.toString());
        } catch (IOException e) {
            LogUtils.printWarnTag(TAG, e.toString());
        } finally {
            closeIO(filein, fileout);
        }
    }

    /**
     * 分享文件
     *
     * @param context  Context
     * @param title    分享标题
     * @param filePath 文件路径
     */
    public static void shareFile(Context context, String title, String filePath) {
        Intent intent = new Intent(Intent.ACTION_SEND);
        Uri uri = Uri.parse("file://" + filePath);
        intent.setType("*/*");
        intent.putExtra(Intent.EXTRA_STREAM, uri);
        context.startActivity(Intent.createChooser(intent, title));
    }

    /**
     * 格式化文件大小
     *
     * @param context Context
     * @param size    文件大小
     * @return
     */
    public static String formatFileSize(Context context, long size) {
        return Formatter.formatFileSize(context, size);
    }

    /**
     * 获取文件类型
     *
     * @param file 文件
     * @return 文件类型
     */
    public static String getMIMEType(File file) {
        String[] files = file.getName().split("\\.");
        String fileType = files[(files.length - 1)];
        if ((fileType.equals("amr")) || (fileType.equals("m4a")) || (fileType.equals("mp3")) || (fileType.equals("mid"))
                || (fileType.equals("xmf")) || (fileType.equals("ogg")) || (fileType.equals("wav"))
                || (fileType.equals("3gpp")) || (fileType.equals("3ga")) || (fileType.equals("wma"))) {
            return "audio/*";
        }

        if ((fileType.equals("3gp")) || (fileType.equals("mp4")) || (fileType.equals("m4v"))) {
            return "video/*";
        }

        if ((fileType.equals("jpg")) || (fileType.equals("gif")) || (fileType.equals("png"))
                || (fileType.equals("jpeg")) || (fileType.equals("bmp"))) {
            return "image/*";
        }

        if (fileType.endsWith("apk")) {
            return "application/vnd.android.package-archive";
        }

        if (fileType.endsWith("doc")) {
            return "application/msword";
        }

        return "*/*";
    }

    /**
     * 根据文件名称获取文件类型
     *
     * @param fileName 文件名称
     * @return 文件类型
     */
    public static String getMIMEType(String fileName) {
        if (StringUtils.isEmpty(fileName)) {
            return "";
        }
        String[] strs = fileName.split("\\.");
        String type = strs[(strs.length - 1)].toLowerCase(Locale.US);
        if ((type.equals("amr")) || (type.equals("m4a")) || (type.equals("mp3")) || (type.equals("mid"))
                || (type.equals("xmf")) || (type.equals("ogg")) || (type.equals("wav")) || (type.equals("3gpp"))
                || (type.equals("3ga")) || (type.equals("wma"))) {
            return "audio/*";
        }

        if ((type.equals("3gp")) || (type.equals("mp4")) || (type.equals("m4v"))) {
            return "video/*";
        }

        if ((type.equals("jpg")) || (type.equals("gif")) || (type.equals("png")) || (type.equals("jpeg"))
                || (type.equals("bmp"))) {
            return "image/*";
        }

        if ((type.equals("xls")) || (type.equals("doc")) || (type.equals("docx")) || (type.equals("xlsx"))) {
            return "word";
        }

        return "*/*";
    }

    /**
     * 通过输入流获取Properties对象
     *
     * @param input 输入流
     * @return
     * @throws IOException
     */
    public static Properties getProperties(InputStream input) throws IOException {
        Properties properties = new Properties();
        properties.load(input);
        return properties;
    }

    /**
     * 获取文件所在的--包名
     *
     * @return 文件所在包名
     */
    public static String getSimplePackage() {
        String str = BaseApplication.getContext().getPackageName();
        int index = str.lastIndexOf(".");
        if (-1 == index) {
            return str;
        }

        return str.substring(index + 1);
    }

    /**
     * 获取应用在SDCard上的工作路径
     *
     * @param packageName 包名
     * @return
     */
    public static String getAppExternalPath(String packageName) {
        StringBuilder sb = new StringBuilder();
        sb.append(Environment.getExternalStorageDirectory().getAbsolutePath());
        sb.append(File.separator);
        sb.append("Android/data/");
        sb.append(packageName);
        return sb.toString();
    }

    /**
     * 判断是否是外部存储目录
     *
     * @param path 文件路径
     * @return
     */
    public static boolean isExternalDataDirectory(String path) {
        return Environment.getExternalStorageDirectory().toString().equals(path);
    }

    /**
     * 判断文件是否存在
     *
     * @param path 文件路径
     * @return
     */
    public static boolean isFileExist(String path) {
        return new File(path).exists();
    }

    /**
     * 判断SD卡是否插入
     *
     * @return true 已经插入
     */
    public static boolean isSDCardExist() {
        return Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED);
    }

    /**
     * 调用手机已安装程序--打开指定路径的文件
     *
     * @param path
     * @return
     */
    public static Intent openFile(String path) {
        Intent intent = new Intent(Intent.ACTION_VIEW);
        intent.addCategory(Intent.CATEGORY_DEFAULT);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        File file = new File(path);
        intent.setDataAndType(Uri.fromFile(file), getMIMEType(path));
        return intent;
    }

    /**
     * 打开图片
     *
     * @param mContext  Context
     * @param imagePath 图片路径
     */
    public static void openImage(Context mContext, String imagePath) {
        Intent intent = new Intent(Intent.ACTION_VIEW);
        intent.addCategory(Intent.CATEGORY_DEFAULT);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        Uri uri = Uri.fromFile(new File(imagePath));
        intent.setDataAndType(uri, "image/*");
        mContext.startActivity(intent);
    }

    /**
     * 打开视频
     *
     * @param mContext  Context
     * @param videoPath 视频路径
     */
    public static void openVideo(Context mContext, String videoPath) {
        Intent intent = new Intent(Intent.ACTION_VIEW);
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        intent.putExtra("oneshot", 0);
        intent.putExtra("configchange", 0);
        Uri uri = Uri.fromFile(new File(videoPath));
        intent.setDataAndType(uri, "video/*");
        mContext.startActivity(intent);
    }

    /**
     * 打开uri
     *
     * @param mContext Context
     * @param mUri     uri
     */
    public static void openURL(Context mContext, String mUri) {
        Uri uri = Uri.parse(mUri);
        Intent intent = new Intent(Intent.ACTION_VIEW, uri);
        mContext.startActivity(intent);
    }

    /**
     * 下载文件
     *
     * @param context  Context
     * @param fileUrl  文件的url
     * @param downPath 下载存储路径 格式如 /Download/
     */
    public static void downloadFile(Context context, String fileUrl, String downPath) {
        DownloadManager.Request request = new DownloadManager.Request(Uri.parse(fileUrl));
        request.setDestinationInExternalPublicDir(downPath, fileUrl.substring(fileUrl.lastIndexOf("/") + 1));
        DownloadManager downloadManager = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);
        downloadManager.enqueue(request);
    }

}
